package com.android.bonn.fast.widget.view;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.Layout;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.TextPaint;
import android.text.style.ForegroundColorSpan;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.TextView;

import com.android.bonn.fast.widget.R;

import java.util.ArrayList;

import androidx.appcompat.widget.AppCompatTextView;

/**
 * 支持文字和九宫图片一起绘制显示
 */
public class ImageTextView extends AppCompatTextView {

    private ArrayMap<String, Bitmap> mBitmaps;
    private BitmapShader[] bitmapShaders;
    private int mHorizontalSpace = 10;
    private int mVerticalSpace = 10;
    private int mRadius = 0;
    private int mImageWidth = 0;
    private int mImageHeight = 0;
    private float mRatio = 1f;
    private int mColumns;
    private int mRows;
    private Matrix matrix = new Matrix();
    private final Paint mPaint = new Paint();
    private final TextPaint mTextPaint;
    private final Paint mTextBgPaint = new Paint();
    private OnClickItemListener onClickItemListener;
    private MotionEvent mEventDown;
    private int mDown;
    private RectF[] mDrawRects;
    private float fontHeight;
    //private Paint.FontMetrics fm;
    //private StaticLayout layout;

    public ImageTextView(Context context) {
        this(context, null);
    }

    public ImageTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ImageTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTextPaint = getPaint();
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ImageTextView);
            try {
                for (int i = 0; i < a.getIndexCount(); i++) {
                    int attr = a.getIndex(i);
                    if (attr == R.styleable.ImageTextView_nineImageHorizontalSpace) {
                        mHorizontalSpace = a.getDimensionPixelSize(attr, mHorizontalSpace);

                    } else if (attr == R.styleable.ImageTextView_nineImageVerticalSpace) {
                        mVerticalSpace = a.getDimensionPixelSize(attr, mVerticalSpace);

                    } else if (attr == R.styleable.ImageTextView_nineImageRadius) {
                        mRadius = a.getDimensionPixelSize(attr, mRadius);

                    } else if (attr == R.styleable.ImageTextView_nineImageRatio) {
                        mRatio = a.getFloat(attr, mRatio);
                    }
                }
            } finally {
                a.recycle();
            }
        }

        mPaint.setAntiAlias(true);
        mTextPaint.setAntiAlias(true);
        setBitmaps(null);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    public void setText(CharSequence text, TextView.BufferType type) {
        super.setText(text, type);

        /*if (!TextUtils.isEmpty(text)) {
            int boundedWidth = getScreenWidth() - getPaddingStart() - getPaddingEnd() - (mRows - 1) * mHorizontalSpace;
            layout = new StaticLayout(getText(), getPaint(), boundedWidth, Layout.Alignment.ALIGN_NORMAL, getLineSpacingMultiplier(), getLineSpacingExtra(), true);
            fontHeight = layout.getHeight();
        } else {
            fontHeight = 0;
        }*/


    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = View.MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);

        int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
        int height = getDefaultSize((int) (getPaddingTop() + getPaddingBottom() + getLayout().getHeight() + getLineSpacingExtra()), heightMeasureSpec);

        if (mBitmaps.size() > 1) {
            width = getDefaultSize(getWidth(), widthMeasureSpec);
            mImageWidth = (width - (mColumns - 1) * mHorizontalSpace - getPaddingStart() - getPaddingEnd()) / mColumns;
            mImageHeight = (int) (mImageWidth * mRatio);
            mRows = (int) Math.ceil(mBitmaps.size() * 1f / mColumns);
            height = measureHeight();
        } else if (mBitmaps.size() == 1) {
            mRows = 1;
            width = mImageWidth;
            height = measureHeight();
        }
        setMeasuredDimension(width, height);


    }

    private int measureHeight() {

        if (getText().length() <= 0) {
            fontHeight = 0;
        }

        return (int) (mImageHeight * mRows + (mRows - 1) * mVerticalSpace + getPaddingTop() + getPaddingBottom() + getLayout().getHeight() + getLineSpacingExtra());
    }


    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        if (mBitmaps.size() > 0) {
            if (getText().length() <= 0) {
                fontHeight = 0;
            } else {
                fontHeight = getLayout().getLineBottom(getLineCount() - 1);
            }
            drawNineBitmap(canvas, fontHeight);
        }


    }

    private void drawNineBitmap(Canvas canvas, float fontHeight) {
        int tempRows = mBitmaps.size() == 4 ? 2 : mRows;
        int tempColumns = mBitmaps.size() == 4 ? 2 : mColumns;
        for (int row = 0; row < tempRows; row++) {

            for (int column = 0; column < tempColumns; column++) {
                int i = row * tempColumns + column;
                boolean isGif;
                if (i >= mBitmaps.size()) {
                    break;
                } else {
                    isGif = mBitmaps.keyAt(i).toLowerCase().contains(".gif");
                }

                BitmapShader mBitmapShader = bitmapShaders[i];

                if (mBitmapShader == null) {
                    return;
                }

                Bitmap bitmap = mBitmaps.valueAt(i);


                float left = getPaddingStart() + column * mHorizontalSpace + column * mImageWidth;
                float top = fontHeight + getPaddingTop() + getLineSpacingExtra() + row * mVerticalSpace + row * mImageHeight;
                float scale;
                float dx = 0, dy = 0;

                int dWidth = bitmap.getWidth();
                int dHeight = bitmap.getHeight();
                int vWidth = mImageWidth;
                int vHeight = mImageHeight;
                if (dWidth * vHeight > vWidth * dHeight) {
                    scale = (float) vHeight / (float) dHeight;
                    dx = (vWidth - dWidth * scale) * 0.5f;
                } else {
                    scale = (float) vWidth / (float) dWidth;
                    dy = (vHeight - dHeight * scale) * 0.5f;
                }

                matrix.setScale(scale, scale);
                matrix.postTranslate(left + Math.round(dx), top + Math.round(dy));

                mBitmapShader.setLocalMatrix(matrix);
                mPaint.setShader(mBitmapShader);

                RectF rectF = new RectF();
                rectF.set(left, top, left + mImageWidth, top + mImageHeight);
                mDrawRects[i] = rectF;
                canvas.drawRoundRect(rectF, mRadius, mRadius, mPaint);

                drawGifLabel(isGif, top, left, canvas);
            }
        }
    }

    private void drawGifLabel(boolean isGif, float top, float left, Canvas canvas) {
        if (isGif) {
            String gifString = "GIF";
            mTextPaint.setTextSize(dpToPx(12));
            mTextPaint.setColor(Color.WHITE);
            Rect bounds = new Rect();
            mTextPaint.getTextBounds(gifString, 0, gifString.length(), bounds);
            mTextBgPaint.setColor(Color.BLACK);
            mTextBgPaint.setAlpha(60);
            RectF rectB = new RectF();
            rectB.set(left + dpToPx(6), top + dpToPx(6),
                    left + dpToPx(6) * 2 + bounds.width(), top + dpToPx(6) * 2 + bounds.height());
            canvas.drawRoundRect(rectB, mRadius, mRadius, mTextBgPaint);
            canvas.drawText(gifString, left + dpToPx(9), top + dpToPx(9) + bounds.height(), mTextPaint);
        }
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    public interface OnClickableSpan {
        boolean onClickableSpan(String text);
    }

    private OnClickableSpan onClickableSpan;

    public void setOnClickableSpan(OnClickableSpan onClickableSpan) {
        this.onClickableSpan = onClickableSpan;
    }

    private boolean clickableSpan(MotionEvent event) {
        if (onClickableSpan != null) {
            int action = event.getAction();
            if ((action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) && getText() instanceof Spanned) {
                performClick();

                int x = (int) event.getX();
                int y = (int) event.getY();
                x -= getTotalPaddingLeft();
                y -= getTotalPaddingTop();
                x += getScrollX();
                y += getScrollY();
                Layout layout = getLayout();
                int line = layout.getLineForVertical(y);
                int off = layout.getOffsetForHorizontal(line, (float) x);
                ForegroundColorSpan[] links = null;


                if (y > layout.getHeight()) {
                    return super.dispatchTouchEvent(event);
                }

                if (getText() instanceof SpannedString) {
                    links = ((SpannedString) getText()).getSpans(off, off, ForegroundColorSpan.class);
                }

                if (getText() instanceof SpannableString) {
                    links = ((SpannableString) getText()).getSpans(off, off, ForegroundColorSpan.class);
                }

                if (links != null && links.length != 0 && action == MotionEvent.ACTION_DOWN) {
                    int csStart = ((Spanned) getText()).getSpanStart(links[0]);
                    int csEnd = ((Spanned) getText()).getSpanEnd(links[0]);
                    return onClickableSpan.onClickableSpan(getText().subSequence(csStart, csEnd).toString());
                }
            }
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return clickableSpan(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return clickImage(event);
    }

    private boolean clickImage(MotionEvent event) {
        boolean isClickItem = false;
        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mEventDown = MotionEvent.obtain(event);
                mDown = getClickItem(mEventDown);
                isClickItem = mDown > -1;
                performClick();
                break;
            case MotionEvent.ACTION_UP:
                if (mEventDown != null) {
                    float distance = (float) Math.sqrt(Math.pow((event.getX() - mEventDown.getX()), 2) + Math.pow((event.getY() - mEventDown.getY()), 2));
                    if (distance < ViewConfiguration.get(getContext()).getScaledTouchSlop()) {
                        int iUp = getClickItem(event);
                        if (mDown == iUp && iUp > -1) {
                            isClickItem = true;
                            if (onClickItemListener != null) {

                                ArrayList<String> objects = new ArrayList<>(mBitmaps.keySet());
                                onClickItemListener.onClick(iUp, objects);
                            }
                        }
                    }
                }
                break;
        }
        return isClickItem;
    }

    private int getClickItem(MotionEvent event) {
        for (int i = 0; i < mDrawRects.length; i++) {
            if (mDrawRects[i] != null && mDrawRects[i].contains(event.getX(), event.getY())) {
                return i;
            }
        }
        return -1;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    public interface OnClickItemListener {
        void onClick(int i, ArrayList<String> url);
    }


    public void setBitmaps(ArrayMap<String, Bitmap> bitmaps) {

        if (bitmaps == null) bitmaps = new ArrayMap<>();
        int newSize = bitmaps.size();
        mBitmaps = bitmaps;
        bitmapShaders = new BitmapShader[newSize];
        mDrawRects = new RectF[newSize];
        if (newSize == 1) {
            mColumns = 1;
        } else {
            mColumns = newSize <= 4 ? 3 : 3;
        }

        for (int i = 0; i < mBitmaps.size(); i++) {
            bitmapShaders[i] = new BitmapShader(mBitmaps.valueAt(i), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        }

        requestLayout();
        //invalidate();


    }


    private void loadBitmap(final int i) {
        setImageRect(i);
    }

    public void setOnClickItemListener(OnClickItemListener onClickItemListener) {
        this.onClickItemListener = onClickItemListener;
    }

    private void setImageRect(int pos) {
        int column = pos / mColumns;
        int row = pos % mColumns;


        int left = getPaddingLeft() + column * mHorizontalSpace + column * mImageWidth;
        int top = getPaddingTop() + row * mVerticalSpace + mImageHeight;
        postInvalidate(left, top, left + mImageWidth, top + mImageHeight);
    }


    private synchronized float dpToPx(float dp) {
        final Resources resources = getContext().getResources();
        final DisplayMetrics metrics = resources.getDisplayMetrics();
        final int unit = TypedValue.COMPLEX_UNIT_DIP;
        return TypedValue.applyDimension(unit, dp, metrics);
    }
}